#include "jmodule.h"
#include <QCoreApplication>
#include <QTECore/jlog.h>
#include <QEventLoop>
#include <QTimer>

namespace QTE
{

typedef std::function<void(void)>  InitFunc;

typedef std::list<InitFunc>  InitFuncList;

typedef std::pair<uint, InitFuncList>  InitFuncListPair;

typedef std::list<InitFuncListPair>  LevelList;

static LevelList &levelList()
{
	static LevelList sLevelList;
	return sLevelList;
}

static inline bool lessThen(const InitFuncListPair &pair1, uint level)
{
	return pair1.first < level;
}

QTECORE_EXPORT int __QTE_module_init_register(const InitFunc &func, uint level)
{
	auto it = std::lower_bound(levelList().begin(), levelList().end(), level, lessThen);

	if( it == levelList().end() or it->first != level )
	{
		it = levelList().insert(it, InitFuncListPair());

		it->first = level;
		it->second.emplace_back(func);
	}

	else
		it->second.emplace_back(func);

	return 0;
}

QTECORE_EXPORT void QTE_module_init_run(int msecs)
{
	if( levelList().empty() )
		return ;

	for(auto &pair : levelList())
	{
		for(auto &func : pair.second)
			func();
	}

	levelList().clear();

	if( msecs <= 0 )
		return ;

	QTimer timer;
	QEventLoop loop;

	QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
	timer.start(msecs);
	loop.exec();
}

typedef std::function<void(int)>  ExitFunc;

typedef std::list<ExitFunc>  ExitFuncList;

static ExitFuncList &exitFuncList()
{
	static ExitFuncList sExitFuncList;
	return sExitFuncList;
}

QTECORE_EXPORT int __QTE_module_exit_register(const ExitFunc &func)
{
	exitFuncList().push_back(func);
	return 0;
}

QTECORE_EXPORT void QTE_exit_run(int exitCode)
{
	for(auto &func : exitFuncList())
		func(exitCode);

	exitFuncList().clear();
}

#define __EXIT(n) \
({ \
	if( qApp ) \
		QCoreApplication::exit(n); \
	else \
		::exit(n); \
})

QTECORE_EXPORT void exit(int exitCode, const QString &text) noexcept
{
	static bool isExit = false;

	if( isExit )
		__EXIT(exitCode);

	isExit = true;
	QTE_exit_run(exitCode);

	if( not text.isEmpty() )
		jInfo() << text;

	__EXIT(exitCode);
}

} //namespace QTE
